package net.io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NonblockingSingleFileHTTPServer
{
	private ByteBuffer contentBuffer;
	private int port = 80;
	public NonblockingSingleFileHTTPServer(ByteBuffer data,String encoding,String MIMEType,int port) throws UnsupportedEncodingException
	{
		this.port = port;
		String header = "HTTP/1.0 200 OK\r\n"
				+"Server:OneFile 2.0\r\n"
				+"Content-length:"+data.limit()+"\r\n"
				+"Content-type:"+MIMEType +"\r\n\r\n";
		byte[] headerDate = header.getBytes("ASICC");
		ByteBuffer buffer = ByteBuffer.allocate(data.limit()+headerDate.length);
		buffer.put(headerDate);
		buffer.put(data);
		buffer.flip();
		this.contentBuffer = buffer;
	}
	public void run() throws IOException 
	{
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		ServerSocket serverSocket = serverSocketChannel.socket();
		Selector selector = Selector.open();
		InetSocketAddress local = new InetSocketAddress(port);
		serverSocket.bind(local);
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		while(true)
		{
			selector.select();
			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
			while(iterator.hasNext())
			{
				SelectionKey next = iterator.next();
				iterator.remove();
				try
				{
					if(next.isAcceptable())
					{
						ServerSocketChannel server = (ServerSocketChannel) next.channel();
						SocketChannel channel = server.accept();
						channel.configureBlocking(false);
						channel.register(selector, SelectionKey.OP_READ);
					}
					else if(next.isWritable())
					{
						SocketChannel channel = (SocketChannel) next.channel();
						ByteBuffer buffer = (ByteBuffer) next.attachment();
						if(buffer.hasRemaining())
						{
							channel.write(buffer);
						}
						else
						{
							channel.close();
						}
					}
					else if(next.isReadable())
					{
						SocketChannel channel = (SocketChannel) next.channel();
						ByteBuffer buffer = ByteBuffer.allocate(4096);
						channel.read(buffer);
						next.interestOps(SelectionKey.OP_WRITE);
						next.attach(contentBuffer.duplicate());
					}
				}
				catch (Exception e)
				{
					next.cancel();
					try
					{
						next.channel().close();
					}
					catch (Exception e2)
					{
					}
				}
			}
		}
	}
	public static void main(String[] args)
	{
		try
		{
			String contentType = "text/plain";
			FileInputStream fin = new FileInputStream("EchoServer.java");
			FileChannel in = fin.getChannel();
			ByteBuffer input = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size());
			int port = 8080;
			String encoding = "ASCII";
			NonblockingSingleFileHTTPServer server = new NonblockingSingleFileHTTPServer(input, encoding, contentType, port);
			server.run();
		}
		catch (Exception e)
		{
		}
	}
}
